package com.zqxx.examine.common.utils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.DefaultParameterHandler;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Intercepts({@org.apache.ibatis.plugin.Signature(method="prepare", type=StatementHandler.class, args={Connection.class})})
public class MyInterceptor
  implements Interceptor
{
  private Page<?> page;
  private static Logger log = LoggerFactory.getLogger(MyInterceptor.class);
  
  public synchronized Object intercept(Invocation invocation)
    throws Throwable
  {
    try
    {
      RoutingStatementHandler handler = (RoutingStatementHandler)invocation.getTarget();
      StatementHandler delegate = (StatementHandler)ReflectUtil.getFieldValue(handler, "delegate");
      BoundSql boundSql = delegate.getBoundSql();
      log.info("拦截sql=" + boundSql.getSql());
      
      MapperMethod.MapperParamMap<?> mapperParamMap = null;
      try
      {
        mapperParamMap = (MapperMethod.MapperParamMap)boundSql.getParameterObject();
      }
      catch (Exception localException1) {}
      if (mapperParamMap == null) {
        return invocation.proceed();
      }
      if (mapperParamMap.containsKey("page"))
      {
        this.page = ((Page)mapperParamMap.get("page"));
        if (this.page == null) {
          throw new Exception("page为空，拦截器不处理数据");
        }
        if (!this.page.isGetAllRecord())
        {
          MappedStatement mappedStatement = (MappedStatement)ReflectUtil.getFieldValue(delegate, "mappedStatement");
          Connection connection = (Connection)invocation.getArgs()[0];
          String strSql = boundSql.getSql();
          
          setTotalRecord(boundSql, mappedStatement, connection);
          StringBuffer sqlBuffer = new StringBuffer(strSql);
          String pageSql = getMySqlPageSql(this.page, sqlBuffer);
          ReflectUtil.setFieldValue(boundSql, "sql", pageSql);
          log.info("修改后的sql=" + pageSql);
        }
      }
    }
    catch (Exception e)
    {
      if (!e.getMessage().equals("page为空，拦截器不处理数据")) {
        e.printStackTrace();
      }
    }
    Object result = invocation.proceed();
    return result;
  }
  
  public Object plugin(Object target)
  {
    return Plugin.wrap(target, this);
  }
  
  public void setProperties(Properties properties) {}
  
  public String getPageSql()
  {
    return null;
  }
  
  public synchronized String getMySqlPageSql(Page<?> page, StringBuffer sqlBuffer)
  {
    int offset = (page.getPageNo() - 1) * page.getPageSize();
    if (!page.isGetAllRecord()) {
      sqlBuffer.append(" limit ").append(offset).append(",").append(page.getPageSize());
    }
    return sqlBuffer.toString();
  }

  /**
   * 参考hibernate的实现完成oracle的分页
   * 
   * @param sql
   * @param page
   * @return String
   */
  public StringBuilder buildPageSqlForOracle(String sql, Page<?> page) {
      StringBuilder pageSql = new StringBuilder(100);
      String beginrow = String.valueOf((page.getPageNo() - 1) * page.getPageSize());
      String endrow = String.valueOf(page.getPageNo() * page.getPageSize());


      pageSql.append("select * from ( select temp.*, rownum row_id from ( ");
      pageSql.append(sql);
      pageSql.append(" ) temp where rownum <= ?");//.append(endrow);
      pageSql.append(") where row_id > ?");//.append(beginrow);
      return pageSql;
  }

  public synchronized String getCountSql(String sql)
  {
    String countSql = "select count(1) from (" + sql + ") sb";
    return countSql;
  }
  
  public synchronized void setTotalRecord(BoundSql boundSql, MappedStatement mappedStatement, Connection connection)
  {
    String sql = boundSql.getSql();
    String countSql = getCountSql(sql);
    System.out.println(countSql);
    



    BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), countSql, boundSql.getParameterMappings(), boundSql.getParameterObject());
    
    ReflectUtil.setFieldValue(countBoundSql, "sql", sql);
    ReflectUtil.setFieldValue(countBoundSql, "parameterMappings", boundSql.getParameterMappings());
    ReflectUtil.setFieldValue(countBoundSql, "parameterObject", boundSql.getParameterObject());
    ReflectUtil.setFieldValue(countBoundSql, "additionalParameters", ReflectUtil.getFieldValue(boundSql, "additionalParameters"));
    ReflectUtil.setFieldValue(countBoundSql, "metaParameters", ReflectUtil.getFieldValue(boundSql, "metaParameters"));
    MapperMethod.MapperParamMap<?> mapperParamMap = (MapperMethod.MapperParamMap)boundSql.getParameterObject();
    

    ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, mapperParamMap, countBoundSql);
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try
    {
      pstmt = connection.prepareStatement(countSql);
      parameterHandler.setParameters(pstmt);
      rs = pstmt.executeQuery();
      if (rs.next())
      {
        int totalRecord = rs.getInt(1);
        this.page.setTotalRecord(totalRecord);
      }
    }
    catch (Exception e)
    {
      e = 
      


        e;e.printStackTrace();
    }
    finally {}
    try
    {
      if (rs != null) {
        rs.close();
      }
      if (pstmt != null) {
        pstmt.close();
      }
    }
    catch (SQLException e)
    {
      e.printStackTrace();
    }
  }
}

